﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace WindowsServiceTscPrint
{
    public class PrintHelpter
    {
        /**
         *打印机需要的json格式数据
      {
	OrderNo:"SG132456789123454878",
	OrderTime:"2020-08-21 02:55:35",
	ShopNo:"ASKDFJLSJDFS12313",
    ShopName:"五大花园店",
	ReceivingArea:"北京(BJ)北京(010)",
	Address:"北京市海淀区知春路65号中国卫星通信大厦B座23层",
	Revicer:"陈独秀",
	Phone:"18828831256",
	Total:"678.00",
	ShipFee:"3.50",
	PointsDiscount:"-178.00元",
	RealPay:"600.00",
	Remark:"测试备注信息",
	DataItems:[
	"肥牛 x2￥59.00",
	"大白菜 x1￥59.00",
	"白萝卜 x3￥59.00",
	"千层肚 x5￥59.00",
	"黄喉 x6￥59.00",
	"菌花 x6￥59.00"
	]
}
         * 
         */

        /// <summary>
        /// 应用名称
        /// </summary>
        static readonly string APP_SHORT_NAME = System.Configuration.ConfigurationManager.AppSettings["appShortName"];

        /// <summary>
        /// 打印机型号/名称
        /// </summary>
        static readonly string PRINT_NAME = System.Configuration.ConfigurationManager.AppSettings["print_name"];

        /// <summary>
        /// 打印机异常提示声音
        /// </summary>
        static readonly string PRINTE_RROR_SOUND = System.Configuration.ConfigurationManager.AppSettings["printErrorSound"];
        /// <summary>
        ///订单来了提示声音
        /// </summary>
        static readonly string ORDER_COME_IN = System.Configuration.ConfigurationManager.AppSettings["ORDER_COME_IN"];

        /// <summary>
        /// 字体设置
        /// </summary>
        static readonly string fontFamily = "宋体";
        //宋体
        //Gloucester MT
        //Gloucester MT Extra Condensed
        //Arial
        //Arial Narrow
        //Bodoni MT Condensed

        /// <summary>
        /// 播放声音，提示打印机异常了
        /// </summary>
        public static void PlaySoundPrinterError()
        {
            Task.Run(() =>
            {
                //播放声音
                try
                {
                    LogHelpter.AddLog("播放打印机异常音频");
                    System.Media.SoundPlayer sndPlayer = new System.Media.SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "\\" + PRINTE_RROR_SOUND);
                    //sndPlayer.PlayLooping();
                    //播放一次
                    sndPlayer.Play();
                    Thread.Sleep(5 * 1000);//播放间隔
                }
                catch (Exception ex)
                {
                    LogHelpter.AddLog("播放声音异常" + ex.ToString());
                }
            });
        }

        /// <summary>
        /// 播放有新订单来了
        /// </summary>
        public static void PlaySoundOrderComming()
        {
            Task.Run(() =>
            {
                //播放声音
                try
                {
                    LogHelpter.AddLog("播放订单来了音频");
                    System.Media.SoundPlayer sndPlayer = new System.Media.SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "\\" + ORDER_COME_IN);
                    //循环播放
                    // sndPlayer.PlayLooping();
                    //播放一次
                    sndPlayer.Play();

                    Thread.Sleep(5 * 1000);//播放间隔
                    //sndPlayer.Stop();
                }
                catch (Exception ex)
                {
                    LogHelpter.AddLog("播放声音异常" + ex.ToString());
                }
            });
        }

        /// <summary>
        /// 给打印机发送打印数据
        /// json格式：
        ///     {
        ///     	OrderNo:"SG132456789123454878",
        ///     	OrderTime:"2020-08-21 02:55:35",
        ///     	ShopNo:"ASKDFJLSJDFS12313",
        ///        ShopName:"五大花园店",
        ///     	ReceivingArea:"北京(BJ)北京(010)",
        ///     	Address:"北京市海淀区知春路65号中国卫星通信大厦B座23层",
        ///     	Revicer:"陈独秀",
        ///     	Phone:"18828831256",
        ///     	Total:"678.00",
        ///     	ShipFee:"3.50",
        ///     	PointsDiscount:"-178.00元",
        ///     	RealPay:"600.00",
        ///     	Remark:"测试备注信息",
        ///     	DataItems:[
        ///     	"肥牛 x2￥59.00",
        ///     	"大白菜 x1￥59.00",
        ///     	"白萝卜 x3￥59.00",
        ///     	"千层肚 x5￥59.00",
        ///     	"黄喉 x6￥59.00",
        ///     	"菌花 x6￥59.00"
        ///     	]
        ///        }
        /// </summary>
        /// <param name="json">要打印的数据</param>
        /// <returns>返回1=表示打印成功，0=失败</returns>
        public static int PrintMsg(string json, out OrderInfo orderInfoOut)
        {
            //开发文档，官网 https://www.chinatsc.cn/SC/support/support_download/TTP-244_Pro/Datasheet
            //驱动下载，客户端测试工具下载，开发文档/DLL下载 https://www.chinatsc.cn/SC/support/support_download/TTP-244_Pro
            //驱动下载，说明书，开发文档/DLL/参考代码下载   http://www.tsc-china.com/info/46592.html
            //打印二维码参考  https://www.chinatsc.cn/Image/Ckeditor/FAQ/DLL打印二维码.pdf
            //tspl2指令集中文版 https://wenku.baidu.com/view/9ab4af374531b90d6c85ec3a87c24028915f8585.html
            //TSC打印机使用教程终极版 https://www.cnblogs.com/codeyou/p/tsc.html
            //TSCLIB.DLL函数库使用说明 https://www.cnblogs.com/liujianshe1990-/p/12602914.html
            //TTP-244 Pro 系列打印机说明书 https://www.chinatsc.cn/SC/DownloadFile/readpdf/support/5712/TTP-244pro_user_manual_2017_2_1_SC.pdf?file_type=0
            //Diagnostic Tool工具，说明书  http://www.tsc-china.com/u/0ee79b3e-d8a9-4f39-9073-78484040ddd3/file/636362389924448747.pdf
            /*
             * 打印机状态值
0		=待機中 
1		=印字頭開啟
2		=卡紙
3		=卡紙並開啟印字頭
4		=缺紙
5		=缺紙並開啟印字頭
8		=缺碳帶
9		=缺碳帶並開啟印字頭
A		=缺碳帶並卡紙
B		=缺碳帶並卡紙及開啟印字頭
C		=缺碳帶並同時缺紙
D		=缺碳帶、缺紙並開啟印字頭
10	=暫停
20	=列印中
             * 
             */

            //读取打印机状态，0=待机中，2=卡纸，4 =缺纸
            int state = TSCLIB_DLL.usbportqueryprinter();
            LogHelpter.AddLog("打印机状态=" + state);
            if (state != 0)
            {
                LogHelpter.AddLog("TSC打印机没有准备好");
                PlaySoundPrinterError();
                orderInfoOut = null;
                return 0;
            }

            OrderInfo orderInfo = null;
            try
            {
                orderInfo = Newtonsoft.Json.JsonConvert.DeserializeObject<OrderInfo>(json);
                string jsonRecive = Newtonsoft.Json.JsonConvert.SerializeObject(orderInfo);
                LogHelpter.AddLog(jsonRecive);
                orderInfoOut = orderInfo;
            }
            catch (Exception ex)
            {
                string msg = "传输的json格式不正确。" + ex.ToString();
                Console.WriteLine(msg);
                LogHelpter.AddLog(msg);
                orderInfoOut = new OrderInfo() { OrderNo = "订单json格式不对" };
                return 0;
            }
            //检查订单信息是否正确
            if (orderInfo == null)
            {
                LogHelpter.AddLog("无效的json格式");
                return 0;
            }
            if (orderInfo.DataItems == null)
            {
                LogHelpter.AddLog("无效的json格式, DataItems不可为空");
                return 0;
            }
            if (string.IsNullOrWhiteSpace(orderInfo.OrderNo))
            {
                LogHelpter.AddLog("OrderNo没有找到");
                return 0;
            }
            if (string.IsNullOrWhiteSpace(orderInfo.Revicer))
            {
                LogHelpter.AddLog("Revicer没有找到");
                return 0;
            }

            LogHelpter.AddLog("************开始打印订单=" + orderInfo.OrderNo);
            //打印收货人地址
            List<string> addressList = new List<string>();
            //店铺地址
            List<string> shopAddressList = new List<string>();
            //打印备注
            List<string> remarkList = new List<string>();
            //食材列表
            List<string> footList = new List<string>();

            //-------------- 收货人地址，长字符串换行计算
            string address = orderInfo.Address;
            if (address.Length <= 12)
            {
                addressList.Add("收货人地址：" + address);
            }
            else
            {
                //第一行
                addressList.Add("收货人地址：" + address.Substring(0, 12));
                //第二行开始，每行18个字符            
                string sy = address.Substring(12);
                const int lineLengthReviceAddress = 18;
                int addressCount = (int)Math.Ceiling(sy.Length / (decimal)lineLengthReviceAddress);
                for (int g = 0; g < addressCount; g++)
                {
                    if (g == addressCount - 1)
                    {//最后一次打印
                        addressList.Add(sy);
                    }
                    else
                    {
                        addressList.Add(sy.Substring(0, lineLengthReviceAddress));
                        sy = sy.Substring(lineLengthReviceAddress);
                    }
                }
            }

            //店铺地址计算
            string shopAddress_5 = orderInfo.ShopAddress;
            if (shopAddress_5.Length <= 13)
            {
                shopAddressList.Add("店铺地址：" + shopAddress_5);
            }
            else
            {
                //第一行
                shopAddressList.Add("店铺地址：" + shopAddress_5.Substring(0, 13));
                //第二行开始，每行14个字符
                string sy = shopAddress_5.Substring(13);
                const int lineLength = 18;
                int addressCount = (int)Math.Ceiling(sy.Length / (decimal)lineLength);
                for (int g = 0; g < addressCount; g++)
                {
                    if (g == addressCount - 1)
                    {//最后一次打印
                        shopAddressList.Add(sy);
                    }
                    else
                    {
                        shopAddressList.Add(sy.Substring(0, lineLength));
                        sy = sy.Substring(lineLength);
                    }
                }
            }

            //--------------备注 ，长字符串换行计算      
            if (orderInfo.Remark.Length <= 10)
            {
                remarkList.Add("备注信息：" + orderInfo.Remark);
            }
            else
            {
                //第一行字
                remarkList.Add("备注信息：" + orderInfo.Remark.Substring(0, 10));
                //第二行开始，每行15个字符      
                string sy = orderInfo.Remark.Substring(10);
                const int remarkSize = 15;
                int countRemark = (int)Math.Ceiling(sy.Length / (decimal)remarkSize);
                for (int g = 0; g < countRemark; g++)
                {
                    if (g == countRemark - 1)
                    {//最后一次打印
                        remarkList.Add(sy);
                    }
                    else
                    {
                        remarkList.Add(sy.Substring(0, remarkSize));
                        sy = sy.Substring(remarkSize);
                    }
                }
            }

            // --------------食材计算，长字符串换行计算
            //foreach (var item in orderInfo.DataItems)
            //{
            //    //一行一列格式,每行18个字符
            //    string foodStr = item.Trim();
            //    const int lineLen = 18;
            //    if (foodStr.Length <= 18)
            //    {
            //        footList.Add(foodStr);
            //    }
            //    else
            //    {
            //        //第一行字
            //        footList.Add(foodStr.Substring(0, lineLen));
            //        //第二行开始，每行18个字符             
            //        string sy = foodStr.Substring(lineLen);
            //        int countFoot = (int)Math.Ceiling(sy.Length / (decimal)lineLen);
            //        for (int g = 0; g < countFoot; g++)
            //        {
            //            if (g == countFoot - 1)
            //            {//最后一次打印
            //                footList.Add(sy);
            //            }
            //            else
            //            {
            //                footList.Add(sy.Substring(0, lineLen));
            //                sy = sy.Substring(lineLen);
            //            }
            //        }
            //    }
            //}

            //    //----------------- 测试打印中文--------------
            //TSCLIB_DLL.openport("TSC TTP-244 Pro");
            TSCLIB_DLL.openport(PRINT_NAME);

            //设置内容显示范围
            // 设置标签 宽度、高度 等信息.
            // 宽 79mm  高40mm（内容高度）
            // 速度为4
            // density字体浓度为15，0~15，数字愈大列印结果愈黑 
            // 使用垂直間距感測器(gap sensor)
            // 两个标签之间的  间距为 3.5mm
            //setup(int width, int height, int speed, int density, int sensor, int sensor_distance, int sensor_offset)
            //宽度、高度、速度、浓度
            //sensor为0：sensor_distance 垂直间距距离 sensor_offset垂直间距的偏移
            //sensor为1：sensor_distance 定义黑标高度和额外送出长度 sensor_offset黑标偏移量
            // int height = 110 + printRows * 7 + countRemark * 7;//内容总高度，单位毫米
            int height = 130 + orderInfo.DataItems.Count * 5 + addressList.Count * 5 + shopAddressList.Count * 5 + remarkList.Count * 7;
            TSCLIB_DLL.setup("79", height.ToString(), "6", "15", "0", "0", "0");

            //设置不回吃纸
            TSCLIB_DLL.nobackfeed();

            //<ESC>!Q 重新开机，测试无效果
            //TSCLIB_DLL.sendcommand("<ESC>!Q");

            TSCLIB_DLL.clearbuffer();
            // 设置 打印的方向.
            TSCLIB_DLL.sendcommand("DIRECTION 1");
            // 纸回拉指定长度
            //TSCLIB_DLL.sendcommand("BACKFEED 60");

            //二维码
            //需要清除上一次的打印记忆
            TSCLIB_DLL.sendcommand("CLS");

            //打印内容距离打印机出口值
            int startY = 320;

            //logo图案，UL5.BMP已经提前存入了打印机FLASH内存
            TSCLIB_DLL.sendcommand("PUTBMP 180," + startY + ", \"UL5.BMP\"");

            startY += 230;
            //应用名称，粗体显示
            TSCLIB_DLL.windowsfont(70, startY, 60, 0, 2, 0, fontFamily, APP_SHORT_NAME);

            //語法：BAR x, y, width, height。画横线,
            //width線條寬度，單位 dot
            //200 DPI: 1 mm = 8 dots 
            //TSCLIB_DLL.sendcommand("BAR 50,0,500,2");

            //QRCODE x,y,ECC Level,cell width,mode,rotation,[justification,]model,]mask,]area] "content"
            //ECC level容错率，H=30%,Q=25%,M=15%
            //cell width 1~10，二维码大小，尺寸
            //画分隔线290，不画270
            startY += 90;
            string command = "QRCODE 20," + startY + ",H,5,A,0,M2,S7,\"" + orderInfo.OrderNo + "\"";
            TSCLIB_DLL.sendcommand(command);

            //设置墨汁浓度  
            //TSCLIB_DLL.sendcommand("DENSITY 15");
            // TSCLIB_DLL.windowsfont(100, 50, 30, 0, 0, 0, fontFamily, "收货区域：北京(BJ)北京(010)");
            //TSS24.BF2简体中文24*24 
            //TSCLIB_DLL.printerfont("100", "0", "FONT001", "0", "1", "1", "收货区域：北京(BJ)北京(010)");
            // TSCLIB_DLL.setup("79", "40", "4", "16", "40", "1", "0");


            //离左侧边距
            int x = 20;
            //离顶部距离
            int y = startY;
            //行高
            int addNum = 40;
            int fontSize =40;

            //收货区域
            TSCLIB_DLL.windowsfont(160, y, fontSize, 0, 0, 0, fontFamily, orderInfo.ReceivingArea + "（" + orderInfo.ShopNo + "）");
            //店铺名称
            TSCLIB_DLL.windowsfont(160, y +80, fontSize, 0, 0, 0, fontFamily, orderInfo.ShopName);
            fontSize = 30;
            y += 100;
            //新行开始----------------------
            //店铺地址，字体加粗
            foreach (var item in shopAddressList)
            {
                TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 2, 0, fontFamily, item);
            }
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "店铺电话：" + orderInfo.ShopTel);
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "收货人：" + orderInfo.Revicer);
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "收货人电话：" + orderInfo.Phone);
            //打印收货地址 ，字体加粗   
            foreach (var item in addressList)
            {
                TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 2, 0, fontFamily, item);
            }
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "订单编号：" + orderInfo.OrderNo);
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "下单时间：" + orderInfo.OrderTime);
            fontSize = 25;
            const string line_xu = "-------------------------------------------";
            TSCLIB_DLL.windowsfont(x, y = y + 20, fontSize, 0, 0, 0, fontFamily, line_xu);
            y = y + addNum;         
            TSCLIB_DLL.windowsfont(x, y, fontSize, 0, 0, 0, fontFamily, "商品");
            TSCLIB_DLL.windowsfont(x + 300, y, fontSize, 0, 0, 0, fontFamily, "数量");
            TSCLIB_DLL.windowsfont(x + 370, y, fontSize, 0, 0, 0, fontFamily, "单价");
            TSCLIB_DLL.windowsfont(x + 480, y, fontSize, 0, 0, 0, fontFamily, "小计");      
            TSCLIB_DLL.windowsfont(x, y = y + 20, fontSize, 0, 0, 0, fontFamily, line_xu);
            //*******食材具体项目： 
            //y = y + addNum;
            // 一行两列格式
            //List<string> lines = new List<string>();
            //string lineN = string.Empty;//每行两个
            //for (int i = 0; i < orderInfo.DataItems.Count; i++)
            //{
            //    lineN = lineN + "；" + orderInfo.DataItems[i];
            //    if ((i + 1) % 2 == 0)
            //    {
            //        lines.Add(lineN);
            //        lineN = "";
            //    }
            //}         
            //orderInfo.DataItems//footList
            foreach (var item in orderInfo.DataItems)
            {
                y = y + 30;
                //拆分#分隔符
                string[] footArr = item.Split('#');
                //食材名称
                TSCLIB_DLL.windowsfont(x, y, fontSize, 0, 0, 0, fontFamily, footArr[0]);
                //数量
                TSCLIB_DLL.windowsfont(x + 300, y, fontSize, 0, 0, 0, fontFamily, footArr[1]);
                //单价
                TSCLIB_DLL.windowsfont(x + 370, y, fontSize, 0, 0, 0, fontFamily, footArr[2]);
                //小计
                TSCLIB_DLL.windowsfont(x + 480, y, fontSize, 0, 0, 0, fontFamily, footArr[3]);
            }
            //食材打印结束，下面打印虚线
            TSCLIB_DLL.windowsfont(x, y = y + 25, fontSize, 0, 0, 0, fontFamily, line_xu);
            fontSize = 30;
            if (!string.IsNullOrWhiteSpace(orderInfo.ShipFee))
            {
                TSCLIB_DLL.windowsfont(x, y = y + addNum - 10, fontSize, 0, 0, 0, fontFamily, "配送费：" + orderInfo.ShipFee);
            }
            //总金额
            TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 2, 0, fontFamily, "总金额：" + orderInfo.Total);

            //******************备注信息，粗体  
            fontSize = 40;
            foreach (var item in remarkList)
            {
                TSCLIB_DLL.windowsfont(x, y = y + 42, fontSize, 0, 2, 0, fontFamily, item);
            }

            ////总计****************
            //fontSize = 35;
            //if (!string.IsNullOrWhiteSpace(orderInfo.Total))
            //{
            //    TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "总计：" + orderInfo.Total + "元");
            //}
            //if (!string.IsNullOrWhiteSpace(orderInfo.PointsDiscount))
            //{
            //    TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "积分折扣：" + orderInfo.PointsDiscount + "元");
            //}
            //TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "运费： " + orderInfo.ShipFee + "元");
            //if (!string.IsNullOrWhiteSpace(orderInfo.TotalDeposit))
            //{
            //    TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "总押金：" + orderInfo.TotalDeposit + "元");
            //}
            //if (!string.IsNullOrWhiteSpace(orderInfo.DailyRent))
            //{
            //    TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 0, 0, fontFamily, "日租金：" + orderInfo.DailyRent + "元");
            //}
            ////实际付款，大字粗体突出显示
            //if (!string.IsNullOrWhiteSpace(orderInfo.RealPay))
            //{
            //    fontSize = 60;
            //    TSCLIB_DLL.windowsfont(x, y = y + addNum, fontSize, 0, 2, 0, fontFamily, "实际支付：" + orderInfo.RealPay + "元");
            //}
            ////测试消息
            //TSCLIB_DLL.windowsfont(x, y = y + 60, 25, 0, 0, 0, fontFamily, "打印时间：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));

            TSCLIB_DLL.printlabel("1", "1");
            TSCLIB_DLL.closeport();
            return 1;
        }

        /// <summary>
        /// 获取打印机状态
        /// </summary>
        public static int GetPrintState()
        {
            try
            {
                //TSCLIB_DLL.openport("TSC TTP-244 Pro");

                //TSCLIB_DLL.openport(PRINT_NAME);
                //读取打印机状态，0=待机中，2=卡纸，4 =缺纸
                int state = TSCLIB_DLL.usbportqueryprinter();
                LogHelpter.AddLog("打印机状态" + state);
                //TSCLIB_DLL.closeport();
                return state;
            }
            catch (Exception ex)
            {
                LogHelpter.AddLog("获取打印机状态异常，" + ex.ToString());
            }
            return 100;
        }
    }
}
